require "utf8Ext"

StringBuilder = StringBuilder or {}

function StringBuilder.new()
    local inst = {}
    
    local charBuff = {}
    local len = 0
    
    function inst:count()
        return len
    end
    
    function inst:get(index)
        assert(index >= 1 and index <= len, "get: out of range")
        return charBuff[index]
    end
    
    function inst:clear()
        for i=1,len do
            charBuff[i] = nil
        end
        len = 0
        return self
    end
    
    --function inst:capacity() end
    
    function inst:copyTo(dst)
        error("todo")
    end
    
    function inst:append(value, index, count)
        local vType = type(value)
        if "string" == vType then
            local tb, ct = string.utf8CharArray(value, index, count, charBuff, len+1)
            len = len + ct
        elseif "number" == vType then
            local str = tostring(value)
            local strLen = #str
            for i=1,strLen do
                charBuff[len+i] = str:sub(i, i)
            end
            len = len + strLen
        else
            error("append: invalid value type: " .. vType)
        end
        return self
    end
    
    function inst:insert(index, value, vIndex, count)
        assert(index >= 1 and index <= len, "insert: out of range")
        
        local vType = type(value)
        if "string" == vType then
            if nil == count then count = string.utf8StringLen(value) end
            
            for i=len,index,-1 do --往后移n个
                charBuff[i+count] = charBuff[i]
            end
            string.utf8CharArray(value, vIndex, count, charBuff, index)
            len = len + count
        elseif "number" == vType then
            for i=len,index,-1 do --往后移1个
                charBuff[i+1] = charBuff[i]
            end
            charBuff[index] = value
            len = len + 1
        else
            error("insert: invalid value type: " .. vType)
        end
        return self
    end
    
    function inst:replace(oldValue, newValue, index, count)
        error("todo")
        --[[
        local vType = type(value)
        if "string" == vType then
        else
            error("replace: invalid value type: " .. vType)
        end
        return self
        ]]
    end
    
    function inst:remove(index, count)
        assert(index >= 1 and index <= len, "remove: out of range")
        local index2 = index + count
        
        if index2 > len then --删除尾部的n个元素
            for i=index,len do
                charBuff[i] = nil
            end
            len = index - 1
        else --删除中间或开头的n个元素
            local j = index
            for i=index2,len do --尾部的元素往前填充
                charBuff[j] =charBuff[i]
                j = j + 1
            end
            for i=j,len do
                charBuff[i] = nil
            end
            len = len - count
        end
        return self
    end
    
    function inst:__tostring()
        if 0 == len then return "" end
        return table.concat(charBuff)
    end
    
    function inst:__len()
        return len
    end
    
    function inst:__index(k)
        assert("number" == type(k), "k not number: " .. k)
        return self:get(k)
    end
    
    function inst:__newindex(k, v)
        assert("number" == type(k), "k not number: " .. k)
        assert("string" == type(v) and 1 == string.utf8StringLen(v), "v not utf8 char: " .. v .. ":" .. type(v))
        charBuff[k] = v
    end
    
    setmetatable(inst, inst)
    return inst
end

function StringBuilder.__call()
    return StringBuilder.new()
end
setmetatable(StringBuilder, StringBuilder)


local function Test1()
    local sb = StringBuilder()
    assert(0 == sb:count(), "count error")
    
    sb:append("中文")
    assert(2 == sb:count(), "append error")
    assert("中" == sb[1], "append error")
    assert("文" == sb[2], "append error")
    assert("中文" == tostring(sb))
    
    sb:append(12)
    assert(4 == sb:count(), "append error")
    assert("中" == sb[1], "append error")
    assert("文" == sb[2], "append error")
    assert("1" == sb[3], "append error")
    assert("2" == sb[4], "append error")
    assert("中文12" == tostring(sb))
    
    sb[4] = "3"
    assert(4 == sb:count(), "append error")
    assert("中" == sb[1], "append error")
    assert("文" == sb[2], "append error")
    assert("1" == sb[3], "append error")
    assert("3" == sb[4], "append error")
    assert("中文13" == tostring(sb))
    
    --sb[4] = 3 --error
    --sb[4] = "aa"
    sb:insert(1, "汉语")
    assert(6 == sb:count(), "insert error")
    assert("汉语中文13" == tostring(sb))
    
    sb:insert(5, 00)
    assert("汉语中文013" == tostring(sb))
    
    sb:insert(3, "。，！")
    assert(10 == sb:count(), "insert error")
    assert("汉语。，！中文013" == tostring(sb))
    
    sb:remove(2, 4)
    assert(6 == sb:count(), "remove error")
    assert("汉中文013" == tostring(sb))
    
    sb:remove(5, 2)
    assert(4 == sb:count(), "remove error")
    assert("汉中文0" == tostring(sb))
    
    sb:remove(4, 10)
    assert(3 == sb:count(), "remove error")
    assert("汉中文" == tostring(sb))
    
    sb:remove(1, 2)
    assert(1 == sb:count(), "remove error")
    assert("文" == tostring(sb))
end

Test1()
